﻿using System.Runtime.InteropServices;

namespace PicView.Core.Sizing;

public static class ImageSizeCalculationHelper
{
    private const int MinTitleWidth = 250;
    private const int Padding = 45;
    
    /// <summary>
    ///  Returns the interface size of the titlebar based on OS
    /// </summary>
    public static double GetInterfaceSize()
    {
        // TODO: find a more elegant solution
        return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 165 : 215;
    }

    public static ImageSize GetImageSize(double width,
        double height,
        ScreenSize screenSize,
        double minWidth,
        double minHeight,
        double interfaceSize,
        double rotationAngle,
        double dpiScaling,
        double uiTopSize,
        double uiBottomSize,
        double galleryHeight,
        double containerWidth,
        double containerHeight)
    {
        if (width <= 0 || height <= 0 || rotationAngle > 360 || rotationAngle < 0)
        {
            return ErrorImageSize(minWidth, minHeight, interfaceSize, containerWidth);
        }

        double aspectRatio;
        double maxWidth, maxHeight;
        var margin = 0d;

        var fullscreen = Settings.WindowProperties.Fullscreen ||
                         Settings.WindowProperties.Maximized;
            
        var borderSpaceHeight = fullscreen ? 0 : uiTopSize + uiBottomSize + galleryHeight;
        var borderSpaceWidth = fullscreen ? 0 : Padding;

        var workAreaWidth = screenSize.WorkingAreaWidth - borderSpaceWidth;
        var workAreaHeight = screenSize.WorkingAreaHeight - borderSpaceHeight;

        if (Settings.Zoom.ScrollEnabled)
        {
            workAreaWidth -= SizeDefaults.ScrollbarSize * dpiScaling;
            containerWidth -= SizeDefaults.ScrollbarSize * dpiScaling;

            maxWidth = Settings.ImageScaling.StretchImage 
                ? workAreaWidth 
                : Math.Min(workAreaWidth - Padding, width);
            
            maxHeight = workAreaHeight;
        }
        else if (Settings.WindowProperties.AutoFit)
        {
            maxWidth = Settings.ImageScaling.StretchImage
                ? workAreaWidth - Padding
                : Math.Min(workAreaWidth - Padding, width);
                    
            maxHeight = Settings.ImageScaling.StretchImage
                ? workAreaHeight - Padding
                : Math.Min(workAreaHeight - Padding, height);
        }
        else
        {
            maxWidth = Settings.ImageScaling.StretchImage
                ? containerWidth
                : Math.Min(containerWidth, width);

            maxHeight = Settings.ImageScaling.StretchImage
                ? containerHeight - galleryHeight
                : Math.Min(containerHeight - galleryHeight, height);
        }

        if (Settings.Gallery.IsBottomGalleryShown)
        {
            if (!Settings.UIProperties.ShowInterface)
            {
                if (Settings.Gallery.ShowBottomGalleryInHiddenUI)
                {
                    margin = galleryHeight > 0 ? galleryHeight : 0;
                }
                else
                {
                    margin = 0;
                }
            }
            else
            {
                margin = galleryHeight > 0 ? galleryHeight : 0;
            }
        }

        // aspect ratio calculation
        switch (rotationAngle)
        {
            case 0:
            case 180:
                aspectRatio = Math.Min(maxWidth / width, maxHeight / height);
                break;

            case 90:
            case 270:
                aspectRatio = Math.Min(maxWidth / height, maxHeight / width);
                break;

            default:
                var rotationRadians = rotationAngle * Math.PI / 180;
                var newWidth = Math.Abs(width * Math.Cos(rotationRadians)) +
                               Math.Abs(height * Math.Sin(rotationRadians));
                var newHeight = Math.Abs(width * Math.Sin(rotationRadians)) +
                                Math.Abs(height * Math.Cos(rotationRadians));
                aspectRatio = Math.Min(maxWidth / newWidth, maxHeight / newHeight);
                break;
        }

        // Fit image by aspect ratio calculation
        // and update values
        double scrollWidth, scrollHeight, xWidth, xHeight;
        if (Settings.Zoom.ScrollEnabled)
        {
            if (fullscreen)
            {
                xWidth = width * aspectRatio;
                xHeight = height * aspectRatio;

                scrollWidth = screenSize.Width;
                scrollHeight = screenSize.Height;
            }
            else if (Settings.WindowProperties.AutoFit)
            {
                xWidth = width * aspectRatio;
                xHeight = height * aspectRatio;

                scrollWidth = Math.Max(xWidth + SizeDefaults.ScrollbarSize, SizeDefaults.WindowMinSize + SizeDefaults.ScrollbarSize + Padding + 16);
                scrollHeight = containerHeight - margin;
            }
            else
            {
                xWidth = containerWidth - SizeDefaults.ScrollbarSize + 10;
                xHeight = height / width * xWidth;
                
                scrollWidth = containerWidth + SizeDefaults.ScrollbarSize;
                scrollHeight = containerHeight - margin;
            }
        }
        else
        {
            scrollWidth = double.NaN;
            scrollHeight = double.NaN;

            xWidth = width * aspectRatio;
            xHeight = height * aspectRatio;
        }

        var titleMaxWidth = GetTitleMaxWidth(rotationAngle, xWidth, xHeight, minWidth, minHeight,
            interfaceSize, containerWidth);

        return new ImageSize(xWidth, xHeight, 0, scrollWidth, scrollHeight, titleMaxWidth, margin, aspectRatio);
    }

    public static ImageSize GetSideBySideImageSize(double width,
        double height,
        double secondaryWidth,
        double secondaryHeight,
        ScreenSize screenSize,
        double minWidth,
        double minHeight,
        double interfaceSize,
        double rotationAngle,
        double dpiScaling,
        double uiTopSize,
        double uiBottomSize,
        double galleryHeight,
        double containerWidth,
        double containerHeight)
    {
        if (width <= 0 || height <= 0 || secondaryWidth <= 0 || secondaryHeight <= 0 || rotationAngle > 360 ||
            rotationAngle < 0)
        {
            return ErrorImageSize(minWidth, minHeight, interfaceSize, containerWidth);
        }

        // Get sizes for both images
        var firstSize = GetImageSize(width, height, screenSize, minWidth, minHeight,
            interfaceSize, rotationAngle, dpiScaling, uiTopSize, uiBottomSize, galleryHeight,
            containerWidth,
            containerHeight);
        var secondSize = GetImageSize(secondaryWidth, secondaryHeight, screenSize, minWidth,
            minHeight, interfaceSize, rotationAngle, dpiScaling, uiTopSize, uiBottomSize,
            galleryHeight,
            containerWidth, containerHeight);

        // Determine maximum height for both images
        var xHeight = Math.Max(firstSize.Height, secondSize.Height);

        // Recalculate the widths to maintain the aspect ratio with the new maximum height
        var xWidth1 = firstSize.Width / firstSize.Height * xHeight;
        var xWidth2 = secondSize.Width / secondSize.Height * xHeight;

        // Combined width of both images
        var combinedWidth = xWidth1 + xWidth2;

        if (Settings.WindowProperties.AutoFit)
        {
            var widthPadding = Settings.ImageScaling.StretchImage ? 4 : Padding;
            var availableWidth = screenSize.WorkingAreaWidth - widthPadding;
            var availableHeight = screenSize.WorkingAreaHeight - (widthPadding + uiBottomSize + uiTopSize);
            if (rotationAngle is 0 or 180)
            {
                // If combined width exceeds available width, scale both images down proportionally
                if (combinedWidth > availableWidth)
                {
                    var scaleFactor = availableWidth / combinedWidth;
                    xWidth1 *= scaleFactor;
                    xWidth2 *= scaleFactor;
                    xHeight *= scaleFactor;

                    combinedWidth = xWidth1 + xWidth2;
                }
            }
            else
            {
                if (combinedWidth > availableHeight)
                {
                    var scaleFactor = availableHeight / combinedWidth;
                    xWidth1 *= scaleFactor;
                    xWidth2 *= scaleFactor;
                    xHeight *= scaleFactor;
                        
                    combinedWidth = xWidth1 + xWidth2;
                }
            }
        }
        else
        {
            if (rotationAngle is 0 or 180)
            {
                if (combinedWidth > containerWidth)
                {
                    var scaleFactor = containerWidth / combinedWidth;
                    xWidth1 *= scaleFactor;
                    xWidth2 *= scaleFactor;
                    xHeight *= scaleFactor;

                    combinedWidth = xWidth1 + xWidth2;
                }
            }
            else
            {
                if (combinedWidth > containerHeight)
                {
                    var scaleFactor = containerHeight / combinedWidth;
                    xWidth1 *= scaleFactor;
                    xWidth2 *= scaleFactor;
                    xHeight *= scaleFactor;
                        
                    combinedWidth = xWidth1 + xWidth2;
                }
            }

        }

        double scrollWidth, scrollHeight;
        if (Settings.Zoom.ScrollEnabled)
        {
            if (Settings.WindowProperties.AutoFit)
            {
                combinedWidth -= SizeDefaults.ScrollbarSize;
                scrollWidth = combinedWidth + SizeDefaults.ScrollbarSize + 8;

                var fullscreen = Settings.WindowProperties.Fullscreen ||
                                 Settings.WindowProperties.Maximized;
                var borderSpaceHeight = fullscreen ? 0 : uiTopSize + uiBottomSize + galleryHeight;
                var workAreaHeight = screenSize.WorkingAreaHeight * dpiScaling - borderSpaceHeight;
                scrollHeight = Math.Min(xHeight,
                    Settings.ImageScaling.StretchImage ? workAreaHeight : workAreaHeight - Padding);
            }
            else
            {
                combinedWidth -= SizeDefaults.ScrollbarSize + 8;
                scrollWidth = double.NaN;
                scrollHeight = double.NaN;
            }
        }
        else
        {
            scrollWidth = double.NaN;
            scrollHeight = double.NaN;
        }

        var titleMaxWidth = GetTitleMaxWidth(rotationAngle, combinedWidth, xHeight, minWidth,
            minHeight, interfaceSize, containerWidth);

        var margin = firstSize.Height > secondSize.Height ? firstSize.Margin : secondSize.Margin;
        return new ImageSize(combinedWidth, xHeight, xWidth2, scrollWidth, scrollHeight, titleMaxWidth, margin,
            firstSize.AspectRatio);
    }


    public static double GetTitleMaxWidth(double rotationAngle, double width, double height, double monitorMinWidth,
        double monitorMinHeight, double interfaceSize, double containerWidth)
    {
        double titleMaxWidth;
        var maximized = Settings.WindowProperties.Fullscreen ||
                        Settings.WindowProperties.Maximized;

        if (Settings.WindowProperties.AutoFit && !maximized)
        {
            switch (rotationAngle)
            {
                case 0 or 180:
                    titleMaxWidth = Math.Max(width, monitorMinWidth);
                    break;
                case 90 or 270:
                    titleMaxWidth = Math.Max(height, monitorMinHeight);
                    break;
                default:
                {
                    var rotationRadians = rotationAngle * Math.PI / 180;
                    var newWidth = Math.Abs(width * Math.Cos(rotationRadians)) +
                                   Math.Abs(height * Math.Sin(rotationRadians));

                    titleMaxWidth = Math.Max(newWidth, monitorMinWidth);
                    break;
                }
            }

            titleMaxWidth = titleMaxWidth - interfaceSize < MinTitleWidth
                ? MinTitleWidth
                : titleMaxWidth - interfaceSize;
        }
        else
        {
            // Fix title width to window size
            titleMaxWidth = containerWidth - interfaceSize <= 0 ? 0 : containerWidth - interfaceSize;
        }

        if (Settings.Zoom.ScrollEnabled)
        {
            if (Settings.ImageScaling.ShowImageSideBySide)
            {
                titleMaxWidth += SizeDefaults.ScrollbarSize + 10;
            }
            else
            {
                titleMaxWidth += SizeDefaults.ScrollbarSize;
            }
        }

        return titleMaxWidth;
    }
    
    private static ImageSize ErrorImageSize(double monitorMinWidth, double monitorMinHeight, double interfaceSize, double containerWidth)
        => new ImageSize(0, 0, 0, 0, 0, GetTitleMaxWidth(0, 0, 0, monitorMinWidth,
                    monitorMinHeight, interfaceSize, containerWidth), 0, 0);
        

    public readonly struct ImageSize(
        double width,
        double height,
        double secondaryWidth,
        double scrollViewerWidth,
        double scrollViewerHeight,
        double titleMaxWidth,
        double margin,
        double aspectRatio)
    {
        public double TitleMaxWidth { get; } = titleMaxWidth;
        public double Width { get; } = width;
        public double Height { get; } = height;

        public double ScrollViewerWidth { get; } = scrollViewerWidth;
        public double ScrollViewerHeight { get; } = scrollViewerHeight;

        public double SecondaryWidth { get; } = secondaryWidth;
        public double Margin { get; } = margin;

        public double AspectRatio { get; } = aspectRatio;
    }
}